import * as vscode from 'vscode';
import * as path from 'path';

export enum DeviceType {
    ESP32 = 'esp32',
    RP2 = 'rp2',
    UNKNOWN = 'unknown'
}

export class StubsManager {
    private extensionPath: string;
    private currentDeviceType: DeviceType = DeviceType.UNKNOWN;
    private isConfigured: boolean = false;

    constructor(context: vscode.ExtensionContext) {
        this.extensionPath = context.extensionPath;
    }

    /**
     * Configure Python analysis to use MicroPython stubs
     */
    public async configureStubs(deviceType: DeviceType = DeviceType.UNKNOWN): Promise<void> {
        const config = vscode.workspace.getConfiguration('micropython');
        const enableIntelliSense = config.get<boolean>('enableIntelliSense', true);

        if (!enableIntelliSense) {
            console.log('MicroPython IntelliSense is disabled');
            return;
        }

        this.currentDeviceType = deviceType;

        // Get stub paths
        const stubPaths = this.getStubPaths(deviceType);

        // Get Python configuration
        const pythonConfig = vscode.workspace.getConfiguration('python');
        const workspaceFolder = vscode.workspace.workspaceFolders?.[0];

        try {
            // Update python.analysis.extraPaths
            const currentExtraPaths = pythonConfig.get<string[]>('analysis.extraPaths', []);
            const newExtraPaths = [...new Set([...currentExtraPaths, ...stubPaths])];

            const configTarget = workspaceFolder
                ? vscode.ConfigurationTarget.Workspace
                : vscode.ConfigurationTarget.Global;

            await pythonConfig.update('analysis.extraPaths', newExtraPaths, configTarget);

            // Also update python.autoComplete.extraPaths for older Pylance versions
            const currentAutoCompletePaths = pythonConfig.get<string[]>('autoComplete.extraPaths', []);
            const newAutoCompletePaths = [...new Set([...currentAutoCompletePaths, ...stubPaths])];
            await pythonConfig.update('autoComplete.extraPaths', newAutoCompletePaths, configTarget);

            this.isConfigured = true;

            const deviceName = deviceType === DeviceType.UNKNOWN ? 'generic' : deviceType;
            vscode.window.showInformationMessage(
                `MicroPython IntelliSense configured for ${deviceName} device`
            );

            console.log(`MicroPython stubs configured: ${stubPaths.join(', ')}`);
        } catch (error) {
            console.error('Failed to configure MicroPython stubs:', error);
            vscode.window.showWarningMessage(
                'Failed to configure MicroPython IntelliSense. You may need to configure it manually.'
            );
        }
    }

    /**
     * Get stub paths for the specified device type
     */
    private getStubPaths(deviceType: DeviceType): string[] {
        const paths: string[] = [];

        // Always include common stubs
        const commonStubsPath = path.join(this.extensionPath, 'stubs', 'common');
        paths.push(commonStubsPath);

        // Add device-specific stubs
        if (deviceType !== DeviceType.UNKNOWN) {
            const deviceStubsPath = path.join(this.extensionPath, 'stubs', deviceType);
            paths.push(deviceStubsPath);
        }

        // Check for custom stubs path in configuration
        const config = vscode.workspace.getConfiguration('micropython');
        const customStubsPath = config.get<string>('customStubsPath');
        if (customStubsPath && customStubsPath.trim()) {
            paths.push(customStubsPath);
        }

        return paths;
    }

    /**
     * Detect device type from system information
     */
    public async detectDeviceType(deviceInfo: string): Promise<DeviceType> {
        const lowerInfo = deviceInfo.toLowerCase();

        if (lowerInfo.includes('esp32')) {
            return DeviceType.ESP32;
        } else if (lowerInfo.includes('rp2') || lowerInfo.includes('pico')) {
            return DeviceType.RP2;
        }

        return DeviceType.UNKNOWN;
    }

    /**
     * Get device information from MicroPython device
     */
    public async getDeviceInfo(sendCommand: (cmd: string) => Promise<string>): Promise<string> {
        try {
            // Try to get sys.implementation
            const response = await sendCommand('import sys; print(sys.implementation)');
            return response;
        } catch (error) {
            console.error('Failed to get device info:', error);
            return '';
        }
    }

    /**
     * Remove MicroPython stubs from Python configuration
     */
    public async removeStubs(): Promise<void> {
        const pythonConfig = vscode.workspace.getConfiguration('python');
        const workspaceFolder = vscode.workspace.workspaceFolders?.[0];

        try {
            const configTarget = workspaceFolder
                ? vscode.ConfigurationTarget.Workspace
                : vscode.ConfigurationTarget.Global;

            // Get current paths
            const currentExtraPaths = pythonConfig.get<string[]>('analysis.extraPaths', []);
            const currentAutoCompletePaths = pythonConfig.get<string[]>('autoComplete.extraPaths', []);

            // Filter out MicroPython stub paths
            const stubsBasePath = path.join(this.extensionPath, 'stubs');
            const filteredExtraPaths = currentExtraPaths.filter(p => !p.includes(stubsBasePath));
            const filteredAutoCompletePaths = currentAutoCompletePaths.filter(p => !p.includes(stubsBasePath));

            // Update configuration
            await pythonConfig.update('analysis.extraPaths', filteredExtraPaths, configTarget);
            await pythonConfig.update('autoComplete.extraPaths', filteredAutoCompletePaths, configTarget);

            this.isConfigured = false;
            this.currentDeviceType = DeviceType.UNKNOWN;

            console.log('MicroPython stubs removed from configuration');
        } catch (error) {
            console.error('Failed to remove MicroPython stubs:', error);
        }
    }

    /**
     * Get current device type
     */
    public getCurrentDeviceType(): DeviceType {
        return this.currentDeviceType;
    }

    /**
     * Check if stubs are configured
     */
    public isStubsConfigured(): boolean {
        return this.isConfigured;
    }
}
